﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using Keeyo.DataHelper.QueryAdapter;
using System.Reflection;
using System.Diagnostics;
using System.Data;

namespace Keeyo.DataHelper
{
    public static class DataUtility
    {
        public static IQuery<T> GetAdapter<T>()
            where T : Entity, new()
        {
            return GetAdapter<T>(ConfigurationManager.ConnectionStrings["DataHelperConnectionString"].ToString());
        }

        public static IQuery<T> GetAdapter<T>(string ConnectionString)
            where T : Entity, new()
        {
            IQuery<T> iq = null;
            string AdapterName = ConfigurationManager.AppSettings["DataHelperAdapterT"];
            if (string.IsNullOrEmpty(AdapterName))
            {
                return new MySql5Adapter<T>() { ConnectionString = ConnectionString };
            }
            else
            {
                switch (AdapterName)
                {
                    case "MySql5Adapter":
                        iq = new MySql5Adapter<T>() { ConnectionString = ConnectionString };
                        break;
                    case "SQL2005Adapter":
                        iq = new SQL2005Adapter<T>() { ConnectionString = ConnectionString };
                        break;
                    case "SQLiteAdapter":
                        iq = new SQLiteAdapter<T>() { ConnectionString = ConnectionString };
                        break;
                    default:
                        iq = GetAdapter<T>(ConfigurationManager.AppSettings["DataHelperAdapterT"].ToString(), ConnectionString);
                        break;
                }
            }
            return iq;

        }

        public static IQuery<T> GetAdapter<T>(string AdapterName, string ConnectionString)
            where T : Entity, new()
        {
            IQuery<T> Query = Assembly.LoadFrom(AdapterName) as IQuery<T>;
            Query.ConnectionString = ConnectionString;
            return new MySql5Adapter<T>();
        }

        public static IQuery GetAdapter()
        {
            return GetAdapter(ConfigurationManager.ConnectionStrings["DataHelperConnectionString"].ToString());
        }

        public static IQuery GetAdapter(string ConnectionString)
        {
            IQuery iq = null;
            string AdapterName = ConfigurationManager.AppSettings["DataHelperAdapterT"];
            if (string.IsNullOrEmpty(AdapterName))
            {
                return new MySql5Adapter() { ConnectionString = ConnectionString };
            }
            else
            {
                switch (AdapterName)
                {
                    case "MySql5Adapter":
                        iq = new MySql5Adapter() { ConnectionString = ConnectionString };
                        break;
                    case "SQL2005Adapter":
                        iq = new SQL2005Adapter() { ConnectionString = ConnectionString };
                        break;
                    case "SQLiteAdapter":
                        iq = new SQLiteAdapter() { ConnectionString = ConnectionString };
                        break;
                    default:
                        iq = GetAdapter(ConfigurationManager.AppSettings["DataHelperAdapterT"].ToString(), ConnectionString);
                        break;
                }
            }
            return iq;
        }

        public static IQuery GetAdapter(string AdapterName, string ConnectionString)
        {
            IQuery Query = Assembly.LoadFrom(AdapterName) as IQuery;
            Query.ConnectionString = ConnectionString;
            return Query;
        }

        public static T ToEntity<T>(this IDataReader Reader, PropertyInfo[] AllowedProperties) where T : Entity, new()
        {
            T Entity = new T();
            if (AllowedProperties == null) AllowedProperties = typeof(T).GetProperties();

            using (Reader)
            {
                EntityBuilder<T> _eb = EntityBuilder<T>.CreateBuilder(Reader, AllowedProperties);
                if (Reader.Read())
                {
                    Entity = _eb.Build(Reader);
                    Entity.IsDBNull = false;
                }
            }
            return Entity;
        }

        public static IList<T> ToListEntity<T>(this IDataReader Reader, PropertyInfo[] AllowedProperties) where T : Entity, new()
        {
            List<T> Entities = new List<T>();
            if (AllowedProperties == null) AllowedProperties = typeof(T).GetProperties();
            using (Reader)
            {
                EntityBuilder<T> _eb = EntityBuilder<T>.CreateBuilder(Reader, AllowedProperties);
                while (Reader.Read())
                {
                    T entity = _eb.Build(Reader);
                    entity.IsDBNull = false;
                    Entities.Add(entity);
                }
            }
            return Entities;
        }

        public static IPagingList<T> ToPagingList<T>(this IEnumerable<T> List, int PageNumber, int PageSize, int TotalItems)
        {
            PagingList<T> pagingList = new PagingList<T>(List, PageNumber, PageSize, TotalItems);
            return pagingList;
        }

        public static T[] ToDataParameter<T>(this Entity entity) where T : IDataParameter, new()
        {
            List<T> dataParameters = new List<T>();
            Type entityType = entity.GetType();

            foreach (PropertyInfo property in entityType.GetProperties())
            {
                string propertyName = GetPropertyName(property);
                T dataParameter = new T();
                dataParameter.ParameterName = "@" + propertyName;
                if (property.PropertyType.BaseType == typeof(Entity))
                {
                    dataParameter.Value = property.PropertyType.GetProperty("ID").GetValue(property.GetValue(entity, null), null);
                }
                else
                {
                    dataParameter.Value = property.GetValue(entity, null);
                }
                if (dataParameter.Value != null)
                {
                    dataParameters.Add(dataParameter);
                }
            }
            return dataParameters.ToArray();
        }

        public static string GetPropertyName(PropertyInfo Property)
        {
            string PropertyName = null;
            NameInDatabaseAttribute NameInDatabase = Attribute.GetCustomAttribute(Property, typeof(NameInDatabaseAttribute), true) as NameInDatabaseAttribute;
            if (NameInDatabase == null)
            {
                PropertyName = Property.Name;
            }
            else
            {
                PropertyName = NameInDatabase.Name;
            }
            return PropertyName;
        }
    }
}
